from django import http
from django.views import View
from django.http import JsonResponse, HttpResponse

from carts.utils import merge_cart_cookie_to_redis
from goods.models import SKU
from users.models import User, Address
from celery_tasks.email.tasks import send_verify_email
# 导入:
from django.contrib.auth import login, logout, authenticate
import logging

from huamei_mall.utils.view import LoginRequiredMixin

logger = logging.getLogger('django')

import json
import re
from django_redis import get_redis_connection

import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','huamei.settings.dev')


class UsernameCountView(View):

    def get(self, request, username):
        '''接收用户名,判断该用户名是否重复注册'''

        # 1.访问数据库,查看该username是否有多个, 把结果赋给一个变量
        try:
            # User.objects.filter(字段=值)
            count = User.objects.filter(username=username).count()
        except Exception as e:
            # 3.如果有问题, 返回json
            return JsonResponse({'code': 400,
                                 'errmsg': '数据库访问出错'})

        # 2.如果没有问题, 返回json
        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'count': count})


class MobileCountView(View):

    def get(self,request,mobile):

        try:
            count = User.objects.filter(mobile=mobile).count()

        except Exception as e:

            return HttpResponse({
                'code': 400,
                'errmsg':'数据库访问出错'
            })
        return HttpResponse({
            'code': 0,
            'errmsg': 'OK',
            'count':count
        })

class RegisterView(View):

    def post(self, request):
        '''接收参数, 保存到数据库'''
        # 1.接收参数
        dict = json.loads(request.body.decode())
        username = dict.get('username')
        password = dict.get('password')
        password2 = dict.get('password2')
        mobile = dict.get('mobile')
        allow = dict.get('allow')
        sms_code_client = dict.get('sms_code')

        # 2.校验(整体)
        if not all([username, password, password2, mobile, allow, sms_code_client]):
            return http.JsonResponse({'code':400,
                                      'errmsg':'缺少必传参数'})

        # 3.username检验
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.JsonResponse({'code': 400,
                                      'errmsg': 'username格式有误'})

        # 4.password检验
        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return http.JsonResponse({'code': 400,
                                      'errmsg': 'password格式有误'})

        # 5.password2 和 password
        if password != password2:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '两次输入不对'})
        # 6.mobile检验
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.JsonResponse({'code': 400,
                                      'errmsg': 'mobile格式有误'})
        # 7.allow检验
        if allow != True:
            return http.JsonResponse({'code': 400,
                                      'errmsg': 'allow格式有误'})

        # 8.sms_code检验 (链接redis数据库)
        redis_conn = get_redis_connection('verify_code')

        # 9.从redis中取值
        sms_code_server = redis_conn.get('sms_%s' % mobile)

        # 10.判断该值是否存在
        if not sms_code_server:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '短信验证码过期'})
        # 11.把redis中取得值和前端发的值对比
        if sms_code_client != sms_code_server.decode():
            return http.JsonResponse({'code': 400,
                                      'errmsg': '验证码有误'})

        # 12.保存到数据库 (username password mobile)
        try:
            user =  User.objects.create_user(username=username,
                                             password=password,
                                             mobile=mobile)
        except Exception as e:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '保存到数据库出错'})
        login(request, user)
        # 13.拼接json返回
        response = http.JsonResponse({'code': 0,
                                 'errmsg': 'ok'})
        response.set_cookie('username',username,3600*24*14)


        return response

class LoginView(View):

    def post(self,request):
        '''定义登录借口'''
        dict = json.loads(request.body.decode())
        # 1获取参数
        username = dict.get('username')
        password = dict.get('password')
        remembered = dict.get('remembered')

        # 2校验参数
        if not all([username,password]):

            return JsonResponse({'code':400,
                                'errmsg':'缺少必传参数'})

        # 3判断用户信息是否正确
        user = authenticate(username=username,
                            password=password)
        # 4判断输入user是否为空
        if user is None:
            return JsonResponse({'code': 400,
                                 'errmsg': '用户不存在或密码错误'})
        # 状态保持
        login(request,user)
        # 判断是否记住密码
        if remembered != True:

            request.session.set_expiry(0)

        else:

            request.session.set_expiry(3600*24*14)

        #保持登录成功响应状态－－－－有效期为２周－－－－对应的是保持用户登录，方便某些操作，如验证邮件，添加地址，购买。。。
        response = http.JsonResponse({'code': 0,
                                      'errmsg': 'ok'})
        response.set_cookie('username', username, 3600 * 24 * 14)


        return response





'''定义退出登录类接口'''
class LogoutView(View):

    def delete(self,request):
        # 删除session
        logout(request)

        response = http.JsonResponse({'code':0,
                                    'errmsg':'OK'})
        # 删除用户名，　response.delete_cookie('username')
        response.delete_cookie('username')
        # 返回响应
        return response



'''判断用户是否登录'''

class UserInfoView(LoginRequiredMixin,View):
    '''用户个人中心'''
    def get(self,request):
        info_data = {
        'username':request.user.username,
        'mobile':request.user.mobile,
        'email':request.user.email,
        'email_active':request.user.email_active
        }
        response = http.JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'info_data': info_data
        })


        response.set_cookie('username',
                            request.user.username,
                            max_age=3600*24*14)

        return response




import logging
logger = logging.getLogger('django')
'''定义添加邮箱接口'''
class EmailView(View):

    def put(self,request):

        json_dict = json.loads(request.body.decode())

        email = json_dict.get('email')

        if not email:
            return JsonResponse({'code': 400,
                                 'errmsg': '邮箱验证失败',})
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({'code': 400,
                                 'errmsg': '邮箱格式有误'})
        try:
            request.user.email = email
            request.user.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400,
                                 'errmsg': '添加邮箱失败'})

        email = '<' + email + '>'
        #verify_url = '邮件验证链接'
        # 用定义好的函数替换原来的字符串:
        verify_url = request.user.generate_verify_email_url()
        # send_verify_email是生产者的任务，不要直接（）调用。把它交给ｗｏｒｋｅｒ
        send_verify_email.delay(email,verify_url)
        #  TODO:给前端发邮件

        return http.JsonResponse({'code': 0,
                                  'errmsg': '添加邮箱成功'})


"""验证邮箱接口"""
class VerifyEmailView(View):

    def put(self, request):
        """实现邮箱验证逻辑"""
        # 接收参数
        token = request.GET.get('token')

        # 校验参数：判断 token 是否为空和过期，提取 user
        if not token:
            return  JsonResponse({'code':400,
                                  'errmsg':'缺少token'})

        # 调用上面封装好的方法, 将 token 传入
        user = User.check_verify_email_token(token)
        if not user:
            return  JsonResponse({'code':400,
                                  'errmsg':'无效的token'})

        # 修改 email_active 的值为 True
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code':400,
                                 'errmsg':'激活邮件失败'})

        # 返回邮箱验证结果
        return JsonResponse({'code':0,
                             'errmsg':'ok'})

'''实现新增地址接口'''
class CreateAddressView(View):

    def post(self,request):
        try:
            #is_deleted 是否逻辑删除了
            count = Address.objects.filter(user=request.user,
                                           is_deleted = False).count()

        except Exception as e:

            return http.JsonResponse({'code':400,
                                           'errmsg':'获取地址数据出错'})
        if count >= 20:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '地址数量过多'})

        # 获取前端发送的响应体字典数据
        json_dict = json.loads(request.body.decode())
        # 获取字典中地址必需的每一个value值
        receiver = json_dict.get('receiver')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')

        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.JsonResponse({'code': 400,
                                      'errmsg': '缺少必传参数'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.JsonResponse({'code': 400,
                                      'errmsg': '参数mobile有误'})

        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.JsonResponse({'code': 400,
                                          'errmsg': '参数tel有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.JsonResponse({'code': 400,
                                          'errmsg': '参数email有误'})

        try:
            #
            address = Address.objects.create(
            user= request.user,
            title = receiver,
            receiver= receiver,
            place = place,
            mobile = mobile ,
            tel = tel,
            email = email,
            province_id = province_id,
            city_id = city_id,
            district_id = district_id
            )
            if not request.user.default_address:
                # 判断有无默认地址，没有则自动添加保存
                request.user.default_address = address
                request.user.save()

        except Exception as e:

            logger.error(e)
            return http.JsonResponse({'code': 400,
                                      'errmsg': '地址新增失败'})
        # 返回给前端的字典
        address_dict = {
            'id':address.id,
            'title':address.title,
            'receiver':address.receiver,
            'place':address.place,
            'mobile':address.mobile,
            'email':address.email,
            'province':address.province.name,
            'city':address.city.name,
            'district':address.district.name
        }
        return http.JsonResponse({'code': 0,
                                  'errmsg': '新增地址成功',
                                  'address_dict':address_dict})


'''展现用户收货地址-----接口'''
class AddressView(View):

    def get(self,request):

        # 获取所有地址。   Address.objects.filter对应的是用户一直以来添加的地址集成表，包括一些逻辑删除但并未展现给用户的地址
        addresses = Address.objects.filter(user = request.user,
                                           is_deleted = False)

        # 地址放到空列表中
        address_dict_list = []
        # 遍历列表，默认地址放前面list.insert(0,value)，其余地址依次加到最后 .append()
        for address in addresses:
            address_dict = {
            'id':address.id,
            'title':address.title,
            'receiver':address.receiver,
            'place':address.place,
            'mobile':address.mobile,
            'email':address.email,
            'province':address.province.name,
            'city':address.city.name,
            'district':address.district.name
            }
            default_address = request.user.default_address

            if address.id == default_address.id:
                address_dict_list.insert(0,address_dict)
            else:
                address_dict_list.append(address_dict)
        default_id = request.user.default_address_id

        # 返回响应
        return http.JsonResponse({
                    "code":0,
                    "errmsg":"ok",
                    "default_address_id":default_id,
                    "addresses":address_dict_list})

'''修改或删除地址－－－－接口'''
class UpdateDestroyAddressView(View):
    def put(self,request,address_id):

        json_dict = json.loads(request.body.decode())

        # 获取字典中地址必需的每一个value值
        receiver = json_dict.get('receiver')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')

        if not all([receiver,place,mobile,province_id,city_id,district_id]):
            return http.JsonResponse({'code': 400,
                                      'errmsg': '缺少必传参数'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.JsonResponse({'code': 400,
                                      'errmsg': '参数mobile有误'})

        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.JsonResponse({'code': 400,
                                          'errmsg': '参数tel有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.JsonResponse({'code': 400,
                                          'errmsg': '参数email有误'})

        try:
            Address.objects.filter(id=address_id).update(
            user= request.user,
            title = receiver,
            receiver= receiver,
            place = place,
            mobile = mobile ,
            tel = tel,
            email = email,
            province_id = province_id,
            city_id = city_id,
            district_id = district_id
            )

        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': 400,
                                      'errmsg': '更新地址失败'})

        # 修改地址信息用字典返回
        address = Address.objects.get(id=address_id)

        address_dict = {
            'id': address.id,
            'title': address.title,
            'receiver': address.receiver,
            'place': address.place,
            'mobile': address.mobile,
            'email': address.email,
            'province': address.province.name,
            'city': address.city.name,
            'district': address.district.name
        }

        return http.JsonResponse({'code': 0,
                                 'errmsg': '修改地址成功',
                                  'address_dicts':address_dict})

    def delete(self,request,address_id):
        # 涉及到数据库操作必须用try语法
        try:
            #　根据地址ＩＤ,查找对应行－－－－记录
            address = Address.objects.get(id=address_id)
            # 是否逻辑删除
            address.is_deleted = True

            address.save()

        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': 400,
                                      'errmsg': '删除地址失败'})

        return http.JsonResponse({
            'code': 0,
            'errmsg': '删除地址成功'
        })


'''修改默认地址接口'''
class DefaultAddressView(View):

    def put(self,request,address_id):
        try:
            address = Address.objects.get(id=address_id)

            request.user.default_address = address

            request.user.save()

        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': 400,
                                      'errmsg': '更改默认地址失败'})

        return http.JsonResponse({'code': 0,
                                      'errmsg': '更改默认地址成功'})

'''修改标题接口'''
class UpdateAddressTitleView(View):

    def put(self,request,address_id):

        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        try:
            address = Address.objects.get(id=address_id)

            title = address.title

            address.save()

        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': 400,
                                      'errmsg': '更改标题失败'})

        return http.JsonResponse({'code': 0,
                                  'errmsg': '更改标题成功'})


'''修改密码接口'''
class UpdatePasswordView(View):

    def put(self,request):

        json_dict = json.loads(request.body.decode())

        old_password = json_dict.get('old_password')
        new_password = json_dict.get('new_password')
        new_password2 = json_dict.get('new_password2')

        password = request.user.password
        # 整体检验
        if not all([old_password,new_password,new_password2]):
            return http.JsonResponse({'code':400,
                                      'errmsg': '缺少必传参数'})
        # 核对２次密码
        #  request.user.check_password(old_password) 校验是否与ｕｓｅｒ表的密码一致
        result = request.user.check_password(old_password)

        if not result:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '原始密码输入错误'})
        # 单个检验
        if not re.match(r'^[a-zA-Z0-9]{8,20}$',new_password):
            return http.JsonResponse({'code': 400,
                                      'errmsg': '更改密码格式错误'})

        if new_password != new_password2:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '新密码输入不一致'})

        try:
            # 将新密码保存到ｕｓｅｒ表中；
            request.user.set_password(new_password)
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': 400,
                                      'errmsg': '更改密码失败'})

        # 清理状态保持信息，让用户回归到登录界面重新登录
        logout(request)
        response = http.JsonResponse({'code': 0,
                                  'errmsg': '密码更改成功'})
        # 删除 cookie中session 保持的信息
        response.delete_cookie('username')

        return response



class UserBrowseHistory(View):
    """用户浏览记录"""

    def post(self, request):
        """保存用户浏览记录"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')

        # 校验参数:
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('sku不存在')

        # 保存用户浏览数据
        redis_conn = get_redis_connection('history')
        pl = redis_conn.pipeline()
        user_id = request.user.id

        # 先去重: 这里给 0 代表去除所有的 sku_id
        pl.lrem('history_%s' % user_id, 0, sku_id)
        # 再存储
        pl.lpush('history_%s' % user_id, sku_id)
        # 最后截取: 界面有限, 只保留 5 个
        pl.ltrim('history_%s' % user_id, 0, 4)
        # 执行管道
        pl.execute()

        # 响应结果
        return http.JsonResponse({'code': 0,
                                  'errmsg': 'OK'})

    '''查询用户浏览记录'''
    def get(self, request):
        """获取用户浏览记录"""
        # 获取Redis存储的sku_id列表信息
        redis_conn = get_redis_connection('history')
        sku_ids = redis_conn.lrange('history_%s' % request.user.id, 0, -1)

        # 根据sku_ids列表数据，查询出商品sku信息
        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image_url,
                'price': sku.price
            })

        return http.JsonResponse({'code': 0,
                                  'errmsg': 'OK',
                                  'skus': skus})


